/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.washington.apl.weather;

import edu.washington.apl.weather.util.WeatherProperties;
import java.util.LinkedList;
import java.util.Queue;

/**
 *
 * @author Ricky
 */
public abstract class WeatherStation {

    public abstract String transformData();
    int humidity = -1;
    double barometricPressure = -1;
    int windDir = -1;
    double windAvg = -1;
    double windGust = -1;
    double rainRate = -1;
    double rainTotal = -1;
    double outdoorTemp = -1;
    int outdoorHumidity = -1;
    double outdoorDewpoint = -1;
    double indoorTemp = -1;
    int indoorHumidity = -1;
    double indoorDewpoint = -1;
    boolean updatesAvailable = false;
    WeatherProperties properties = WeatherProperties.getInstance();
    WeatherUpdateEvent updateListener = new WeatherUpdateEvent() {
        @Override
        public void weatherEvent(WeatherStation station, long timeOfEvent) {
        }
    };

    static public double toInches(double millibars) {
        return 0.02953 * millibars;
    }

    static public double toMillibars(double inches) {
        return inches / 0.02953;
    }

    static public double toC(double f) {
        return (f - 32.0) * (5.0 / 9.0);
    }

    static public double toF(double c) {
        return (c * (9.0 / 5.0)) + 32.0;
    }

    static public double fromMsToMph(double ms) {
        return ms * 2.2369362920544;
    }

//    private class WindEntry {
//
//        public WindEntry(int speed, int direction) {
//            this.timestamp = System.currentTimeMillis();
//            this.speed = speed;
//            this.direction = direction;
//        }
//        
//        long timestamp;
//        int speed;
//        int direction;
//    }
//    
//    Queue<WindEntry> windEntries = new LinkedList<>();
//    
//    public void addWindSpeed(int speed, int direction) {
//        windEntries.add(new WindEntry(speed, direction));
//    }
//    
//    public int getAverageWindSpeed(int period) {
//        return 0;
//    }
//    
//    public int getMaximumWindSpeed(int period) {
//        return 0;
//    }
//    
//    public int getWindSpeed( ) {
//        return 0;
//    }
//        
    public synchronized WeatherUpdateEvent getUpdateListener() {
        return updateListener;
    }

    public synchronized void setUpdateListener(WeatherUpdateEvent updateListener) {
        this.updateListener = updateListener;
    }

    public synchronized int getHumidity() {
        if (humidity == -1) {
            throw new UnsupportedOperationException("Humidity not available");
        }
        return humidity;
    }

    public synchronized double getBarometricPressure() {
        if ((barometricPressure == -1) || (properties.getBooleanProperty("station.barometer.enabled", true) == false)) {
            throw new UnsupportedOperationException("Barometric Pressure not available");
        }
        double offset = Double.valueOf(properties.getProperty("station.barometer.offset", "0.0"));
        return barometricPressure + offset;
    }

    public synchronized int getWindDir() {
        if (windDir == -1) {
            throw new UnsupportedOperationException("Wind Direction not available");
        }

        return windDir;
    }

    public synchronized double getWindAvg() {
        if (windAvg == -1) {
            throw new UnsupportedOperationException("Wind Average not available");
        }
        return windAvg;
    }

    public synchronized double getWindGust() {
        if (windGust == -1) {
            throw new UnsupportedOperationException("Wind Gust not available");
        }
        return windGust;
    }

    public synchronized double getRainRate() {
        if (rainRate == -1) {
            throw new UnsupportedOperationException("rainRate not available");
        }
        return rainRate;
    }

    public synchronized double getRainTotal() {
        if (rainTotal == -1) {
            throw new UnsupportedOperationException("rainTotal not available");
        }
        return rainTotal;
    }

    public synchronized double getOutdoorTemp() {
        if ((outdoorTemp == -1) || (properties.getBooleanProperty("station.outdoor.temperature.enabled", true) == false)) {
            throw new UnsupportedOperationException("outdoorTemp not available");
        }
        return outdoorTemp;
    }

    public synchronized int getOutdoorHumidity() {
        if ((outdoorHumidity == -1) || (properties.getBooleanProperty("station.outdoor.humidity.enabled", true) == false)) {
            throw new UnsupportedOperationException("outdoorHumidity not available");
        }
        return outdoorHumidity;
    }

    public synchronized double getOutdoorDewpoint() {

        if (properties.getBooleanProperty("station.outdoor.dewpoint.calculated", false)) {
            double X = 1 - (0.01 * (double) getOutdoorHumidity());
            double Tc = toC(getOutdoorTemp());
            double K = Tc - (14.55 + 0.114 * Tc) * X - Math.pow((2.5 + 0.007 * Tc) * X,
                    3.0) - (15.9 + 0.117 * Tc) * Math.pow(X, 14.0);
            outdoorDewpoint = (K*1.8)+32;
        }

        if ((outdoorDewpoint == -1) || (properties.getBooleanProperty("station.outdoor.dewpoint.enabled", true) == false)) {
            throw new UnsupportedOperationException("outdoorDewpoint not available");
        }
        return outdoorDewpoint;
    }

    public synchronized double getIndoorTemp() {
        if (indoorTemp == -1) {
            throw new UnsupportedOperationException("indoorTemp not available");
        }
        return indoorTemp;
    }

    public synchronized double getIndoorHumidity() {
        if (indoorHumidity == -1) {
            throw new UnsupportedOperationException("indoorHumidity not available");
        }
        return indoorHumidity;
    }

    public synchronized double getIndoorDewpoint() {
        if (indoorDewpoint == -1) {
            throw new UnsupportedOperationException("indoorDewpoint not available");
        }
        return indoorDewpoint;
    }

    public synchronized void setHumidity(int humidity) {
        this.humidity = humidity;
        updatesAvailable = true;
    }

    /**
     *
     * @param barometricPressure inches
     */
    public synchronized void setBarometricPressure(double barometricPressure) {
        this.barometricPressure = barometricPressure;
        updatesAvailable = true;
    }

    /**
     *
     * @param windDir mph
     */
    public synchronized void setWindDir(int windDir) {
        this.windDir = windDir;
        updatesAvailable = true;
    }

    /**
     *
     * @param windAvg mph
     */
    public synchronized void setWindAvg(double windAvg) {
        this.windAvg = windAvg;
        updatesAvailable = true;
    }

    /**
     *
     * @param windGust mph
     */
    public synchronized void setWindGust(double windGust) {
        this.windGust = windGust;
        updatesAvailable = true;
    }

    /**
     *
     * @param rainRate in/hr
     */
    public synchronized void setRainRate(double rainRate) {
        this.rainRate = rainRate;
        updatesAvailable = true;
    }

    /**
     *
     * @param rainTotal in/hr
     */
    public synchronized void setRainTotal(double rainTotal) {
        this.rainTotal = rainTotal;
        updatesAvailable = true;
    }

    /**
     *
     * @param outdoorTemp F
     */
    public synchronized void setOutdoorTemp(double outdoorTemp) {
        this.outdoorTemp = outdoorTemp;
        updatesAvailable = true;
    }

    /**
     *
     * @param outdoorHumidity %
     */
    public synchronized void setOutdoorHumidity(int outdoorHumidity) {
        this.outdoorHumidity = outdoorHumidity;
        updatesAvailable = true;
    }

    /**
     *
     * @param outdoorDewpoint F
     */
    public synchronized void setOutdoorDewpoint(double outdoorDewpoint) {
        this.outdoorDewpoint = outdoorDewpoint;
        updatesAvailable = true;
    }

    /**
     *
     * @param indoorTemp F
     */
    public synchronized void setIndoorTemp(double indoorTemp) {
        this.indoorTemp = indoorTemp;
        updatesAvailable = true;
    }

    /**
     *
     * @param indoorHumidity %
     */
    public synchronized void setIndoorHumidity(int indoorHumidity) {
        this.indoorHumidity = indoorHumidity;
        updatesAvailable = true;
    }

    /**
     *
     * @param indoorDewpoint F
     */
    public synchronized void setIndoorDewpoint(double indoorDewpoint) {
        this.indoorDewpoint = indoorDewpoint;
        updatesAvailable = true;
    }

    public static void main(String[] args) {
                    double X = 1 - (0.01 * (double) 50);
            double Tc = toC(50);
            double K = Tc - (14.55 + 0.114 * Tc) * X - Math.pow((2.5 + 0.007 * Tc) * X,
                    3.0) - (15.9 + 0.117 * Tc) * Math.pow(X, 14.0);
            double outdoorDewpoint = (K*1.8)+32;
            System.err.println(outdoorDewpoint);

    }
}
